package com.zwh.autoconfigure.interceptor;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.zwh.common.persistence.ReturnObject;
import com.zwh.common.persistence.ReturnStatus;
import com.zwh.common.utils.servlet.MyCachingRequestWrapper;
import com.zwh.common.web.http.ServletUtils;


/**
 * 接口签名校验拦截器
 *
 * @author zwh
 * @date 2020/12/9 14:45
 **/
public class CommonSignValidFilter implements Filter {
    private static String encoding = "UTF-8";
    private static final String contentType = "application/json; charset=" + encoding;
    private static final String contentTypeForIE = "text/html; charset=" + encoding;
    private boolean forIE = false;
    public static final String PARAM_NAME_EXCLUSIONS = "exclusions";
    public static final String HEADER_SIGN_NAME = "rsa_sign";
    /**
     * 不被拦截的请求requestURI
     */
    public Set<String> urlList = new HashSet<>();

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        String param = filterConfig.getInitParameter(PARAM_NAME_EXCLUSIONS);
        if (StringUtils.isNoneEmpty(param)) {
            String[] excludeUri = param.split(",");
            Collections.addAll(urlList, excludeUri);
        }
    }

    @Override
    public void destroy() {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        boolean isExclude = false;
//        HttpServletRequest httpServletRequest = servletRequestAttributes.getRequest();
        MyCachingRequestWrapper httpServletRequest = new MyCachingRequestWrapper(servletRequestAttributes.getRequest());
        for (String url : urlList) {
            if (httpServletRequest.getRequestURI().contains(url)) {
                isExclude = true;
                break;
            }
        }
        //这句话是解决乱码的
        servletResponse.setCharacterEncoding("UTF-8");

        String sign = httpServletRequest.getHeader(HEADER_SIGN_NAME);

        //处理过滤的uri
        if (!isExclude) {
            ReturnObject data = ReturnObject.fail("签名校验失败！", "403");
            if (StringUtils.isEmpty(sign)) {
                returnErrorJson(httpServletRequest, servletResponse, data);
                return;
            }
            Map<String, String> map = null;

            if (httpServletRequest.getMethod().toUpperCase(Locale.ENGLISH).equals("GET")) {
                // get请求
                Map<String, Object> pathData = ServletUtils.getParameters(httpServletRequest);
                map = JSONObject.parseObject(JSONObject.toJSONString(pathData), new TypeReference<Map<String, String>>() {
                });
            } else {
                // post请求
                String jsonParam = httpServletRequest.getBodyString();
                try {
                    map = JSONObject.parseObject(jsonParam, new TypeReference<Map<String, String>>() {
                    });
                } catch (Exception e) {
                    // 不是json数据
                    try {
                        Map<String, Object> bodyData = this.getUrlParams(jsonParam);
                        map = JSONObject.parseObject(JSONObject.toJSONString(bodyData), new TypeReference<Map<String, String>>() {
                        });
                    } catch (Exception ex) {
                        data.setMessage("未知请求数据异常");
                        data.setStatus(ReturnStatus.STATUS_GLOBAL_WARN_MESSAGE);
                        returnErrorJson(httpServletRequest, servletResponse, data);
                        return;
                    }
                }
            }

            if (map != null) {
                // 参数校验
                TreeMap<String, String> treeMap = new TreeMap<>(map);
                List<String> keyValues = new ArrayList<>();
                for (Map.Entry<String, String> entry : treeMap.entrySet()) {
                    if (!StringUtils.isEmpty(entry.getValue())) {
                        // 空的参数不参与签名
                        keyValues.add(entry.getKey() + "=" + entry.getValue());
                    }
                }
                String params = StringUtils.join(keyValues, "&");
                String checkSign = null;
                try {
                    checkSign = "签名";//SignUtils.sign(Global.getConfig("publicKey", ""), Global.getConfig("privateKey", ""), params, "");
                } catch (Exception e) {
                    data.setMessage(e.getMessage());
                    returnErrorJson(httpServletRequest, servletResponse, data);
                    return;
                }
                if (!sign.equals(checkSign)) {
                    returnErrorJson(httpServletRequest, servletResponse, data);
                    return;
                }
            }
        }
        filterChain.doFilter(httpServletRequest, servletResponse);
    }

    private void returnErrorJson(HttpServletRequest httpServletRequest, ServletResponse servletResponse, ReturnObject returnObject) throws IOException {
        servletResponse.setContentType(isIE(httpServletRequest) ? contentTypeForIE : contentType);
        servletResponse.getWriter().print(JSONObject.toJSONString(returnObject));
    }

    private boolean isIE(HttpServletRequest request) {
        String agent = request.getHeader("User-Agent").toLowerCase();
        if (agent.indexOf("msie") > 0) {
            return true;
        }
        if (agent.indexOf("gecko") > 0 && agent.indexOf("rv:11") > 0) {
            return true;
        }
        return false;
    }

    public static Map<String, Object> getUrlParams(String param) {
        Map<String, Object> map = new HashMap<String, Object>();
        if (StringUtils.isBlank(param)) {
            return map;
        }
        String[] params = param.split("&");
        for (int i = 0; i < params.length; i++) {
            String[] p = params[i].split("=");
            if (p.length == 2) {
                map.put(p[0], p[1]);
            } else {
                map.put(p[0], null);
            }
        }
        return map;
    }
}
